﻿using System;
using System.Timers;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ANZ_AIM_GUI.Utils;
using ANZ_AIM_FRAMEWORK;
using ANZ_AIM_BLL;
using ANZ_AIM_BLL.Model;
using System.Reflection;
using log4net;

namespace ANZ_AIM_GUI
{
    public partial class frmLogin : Form
    {
        //log4net
        private static readonly ILog logger = LogManager.GetLogger(typeof(frmLogin));

        public const int LOGIN_OK = 1;
        public const int LOGIN_OK_WITH_REMINDER = 2;
        public const int LOGIN_FAILED_USER_NOT_FOUND = -1;
        public const int LOGIN_FAILED_USER_INACTIVE = -2;
        public const int LOGIN_FAILED_PASSWORD = -3;
        public const int LOGIN_FAILED_USER_LOCKED = -4;

        protected AppParam appParam = AppParam.Instance;

        private frmMain frmMain;
        private System.Timers.Timer _delayTimer;
        public bool NeedToChangePwd;

        public bool IsActive = true;

        public int RemainingDays;

        private int PwdWrongCount;

        public frmLogin()
        {
            InitializeComponent();
            this.btnOK.DialogResult = DialogResult.OK;
            this.NeedToChangePwd = false;

        }

        public frmLogin(frmMain frmMain)
            : this()
        {
            this.frmMain = frmMain;
            this.NeedToChangePwd = false;

        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            Close();
        }
        private void delay()
        {
            _delayTimer = new System.Timers.Timer();
            _delayTimer.Interval = 30000;
            _delayTimer.Elapsed += (o, e) => afterDelay();
            _delayTimer.Start();
        }
        private void afterDelay()
        {
            _delayTimer.Stop();
            this.Invoke((Action)delegate()
            {
                enableComponent(true);
                UserBLL userBll = new UserBLL();
                User user = userBll.GetByUsername(this.txtUsername.Text.ToLower());
                user.IsLock = false;
                user.LockDate = null;
                userBll.Save(user);
                this.PwdWrongCount = 0;
                this.btnOK.Focus();
            });

        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            var msg = String.Empty;
            try
            {
                if (string.IsNullOrEmpty(txtUsername.Text))
                {
                    MessageBox.Show("Please input your Username/Password.", Constant.SYS_ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    this.DialogResult = DialogResult.None;
                    return;
                }

                if (string.IsNullOrEmpty(txtPassword.Text))
                {
                    MessageBox.Show("Please input your Username/Password.", Constant.SYS_ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    this.DialogResult = DialogResult.None;
                    return;
                }

                switch (LoginClicked())
                {
                    case LOGIN_FAILED_USER_NOT_FOUND:
                        msg = Constant.SYS_MSG_INCORRECT_USR_PASS;
                        MessageBox.Show(Constant.SYS_MSG_INCORRECT_USR_PASS, Constant.SYS_ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        this.DialogResult = DialogResult.None;
                        break;
                    case LOGIN_FAILED_USER_INACTIVE:
                        msg = Constant.SYS_MSG_USR_INACTIVE;
                        MessageBox.Show(Constant.SYS_MSG_USR_INACTIVE, Constant.SYS_ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        this.DialogResult = DialogResult.None;
                        break;
                    case LOGIN_FAILED_PASSWORD:
                        msg = Constant.SYS_MSG_INCORRECT_USR_PASS;
                        MessageBox.Show(Constant.SYS_MSG_INCORRECT_USR_PASS, Constant.SYS_ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        this.DialogResult = DialogResult.None;
                        break;
                    case LOGIN_OK:
                        msg = Constant.SYS_MSG_LOGIN_OK;
                        this.DialogResult = DialogResult.Yes;
                        break;
                    case LOGIN_OK_WITH_REMINDER:
                        msg = Constant.SYS_MSG_LOGIN_OK;
                        // MessageBox.Show(string.Format("You must change your password in {0} day(s)", ctlLogin.RemainingDays), Constant.SYS_WARNING, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        this.DialogResult = DialogResult.Yes;
                        break;
                    case LOGIN_FAILED_USER_LOCKED:
                        msg = Constant.SYS_MSG_USR_LOCKED_TIME;
                        MessageBox.Show(Constant.SYS_MSG_USR_LOCKED_TIME, Constant.SYS_ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        enableComponent(false);

                        delay();

                        this.DialogResult = DialogResult.None;
                        break;
                    default:
                        msg = "Invalid login type";
                        break;
                }
                this.NeedToChangePwd = NeedToChangePassword(txtUsername.Text.Trim());

            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.InnerException == null ? ex.Message : ex.InnerException.Message, Constant.SYS_ERROR, MessageBoxButtons.OK);
                logger.Error(ex.Message + " - " + ex.StackTrace);
                return;
            }

            try
            {
                if (!String.IsNullOrEmpty(msg))
                {
                    LogBLL logBll = new LogBLL();
                    logBll.Description = msg;
                    logBll.Log(this.FindForm(), appParam.UserName);
                }
            }
            catch { }
        }

        private void tmrLocked_Tick(object sender, EventArgs e)
        {
            btnOK.Enabled = true;
        }

        public int LoginClicked()
        {
            try
            {
                string username = txtUsername.Text.ToLower();
                string password = txtPassword.Text;

                // encrypt input password
                AESHelper aes = new AESHelper();
                password = aes.EncryptToString(password);

                UserBLL userBll = new UserBLL();
                User user = userBll.GetByUsername(username);
                if (user == null)
                {
                    return LOGIN_FAILED_USER_NOT_FOUND;
                }

                if (user.IsActive == false)
                {
                    IsActive = false;
                    return LOGIN_FAILED_USER_INACTIVE;
                }
                if (user.IsLock == true)
                {
                    int diffSecond = DateTime.Now.Subtract(user.LockDate.Value).Seconds;
                    if (diffSecond < GetParamLockTime())
                    {

                        return LOGIN_FAILED_USER_LOCKED;
                    }
                    user.IsLock = false;
                    userBll.Save(user);
                }
                if (user.Password != password)
                {
                    this.PwdWrongCount++;
                    if (this.PwdWrongCount >= GetParamMaxLogin())
                    {
                        user.IsLock = true;
                        user.LockDate = MiscHelper.DateTimeToShort(DateTime.Now);
                        userBll.Save(user);


                        return LOGIN_FAILED_USER_LOCKED;
                    }
                    return LOGIN_FAILED_PASSWORD;
                }

                appParam.LoggedIn = true;
                appParam.UserId = user.UserID;
                appParam.UserName = user.UserName;
                string[] userRoles = user.Role.Split(',');
                appParam.Role = userRoles;
                appParam.PathFile = Application.StartupPath;

                int reminderDay = GetParamReminderDay();
                int expireDay = GetParamExpireDay();

                int passedDays = 0; // Calculate days from last change pass to today.
                if (!user.LastChangedPwd.HasValue)
                {
                    user.LastChangedPwd = MiscHelper.DateTimeToShort(DateTime.Now.AddDays(-expireDay));
                    userBll.Save(user);
                }
                else
                {
                    passedDays = DateTime.Now.Subtract(user.LastChangedPwd.Value).Days;
                }

                this.RemainingDays = expireDay - passedDays;
                if (this.RemainingDays == 0)
                {
                    this.NeedToChangePwd = true;
                    user.MustChangePwd = "Y";
                    userBll.Save(user);
                }
                if (this.RemainingDays <= reminderDay && this.RemainingDays > 0)
                {
                    return LOGIN_OK_WITH_REMINDER;
                }


                return LOGIN_OK;
            }
            catch (Exception ex) { throw ex; }
        }

        public void enableComponent(bool isEnabled)
        {
            this.txtUsername.Enabled = isEnabled;
            this.txtPassword.Enabled = isEnabled;
            this.btnOK.Enabled = isEnabled;
            this.btnCancel.Enabled = isEnabled;
        }

        public static bool NeedToChangePassword(string userName)
        {
            try
            {
                UserBLL userBll = new UserBLL();
                User user = userBll.GetByUsername(userName);

                if (user == null)
                {
                    return false;
                }
                int dayToExpire = GetParamExpireDay();
                if (user.LastChangedPwd.HasValue &&
                    DateTime.Now.Subtract(user.LastChangedPwd.Value).Days > dayToExpire)
                {
                    user.MustChangePwd = "Y";
                    userBll.Save(user);
                }

                return user.MustChangePwd == "Y";
            } 
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// Get Max Wrong password time from database, if not defines, set default = 3.
        /// </summary>
        /// <returns>Max login.</returns>
        public static int GetParamMaxLogin()
        {
            try
            {
                int maxDefault = 3; // Default Max Wrong Password
                ConfigurationBLL configBll = new ConfigurationBLL();
                Configuration config = configBll.GetByKey(Configuration.USER_LOGIN_PARAM__MAX_WRONG_PWD);
                int newMax = maxDefault;
                if (config != null && !string.IsNullOrEmpty(config.ConfigValue))
                {
                    if (int.TryParse(config.ConfigValue, out newMax))
                    {

                    }
                }

                return newMax;
            }
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// Get Expire day from database, if not defines, set default = 30.
        /// </summary>
        /// <returns></returns>
        public static int GetParamExpireDay()
        {
            try
            {
                int dayToExpire = 60; // Default Value.
                ConfigurationBLL configBll = new ConfigurationBLL();
                Configuration config = configBll.GetByKey(Configuration.USER_LOGIN_PARAM__EXPIRE_AFTER);
                if (config != null && !string.IsNullOrEmpty(config.ConfigValue))
                {
                    if (int.TryParse(config.ConfigValue, out dayToExpire))
                    {

                    }
                }

                return dayToExpire;
            }
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// Get Reminder day from database, if not defines, set default = 5.
        /// </summary>
        /// <returns></returns>
        public static int GetParamReminderDay()
        {
            try
            {
                int reminderDay = 5; // Default.
                ConfigurationBLL configBll = new ConfigurationBLL();
                Configuration config = configBll.GetByKey(Configuration.USER_LOGIN_PARAM__DAY_REMINDER_PWD);
                if (config != null && !string.IsNullOrEmpty(config.ConfigValue))
                {
                    if (int.TryParse(config.ConfigValue, out reminderDay))
                    {
                    }
                }

                return reminderDay;
            }
            catch (Exception ex) { throw ex; }
        }

        public static int GetParamLockTime()
        {
            try
            {
                int lockTime = 30; // Default.
                ConfigurationBLL configBll = new ConfigurationBLL();
                Configuration config = configBll.GetByKey(Configuration.LOCK_TIME);
                if (config != null && !string.IsNullOrEmpty(config.ConfigValue))
                {
                    if (int.TryParse(config.ConfigValue, out lockTime))
                    {
                    }
                }

                return lockTime;
            }
            catch (Exception ex) { throw ex; }
        }

        private void frmLogin_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (appParam.UserName == null)
            {
                Application.Exit();
            }

        }

        private void frmLogin_Load(object sender, EventArgs e)
        {

        }


    }
}
